#include <slothttpd/http/request.hpp>
#include <slothttpd/logger.hpp>
#include <slothttpd/ngx_parser/ngx_string.h>

#include <cstring>
#include <iostream>

#include <boost/range/algorithm/copy.hpp>
#include <boost/algorithm/string/compare.hpp>

namespace slothttpd {
namespace http {

request::request() :
    http_version(std::make_pair(0, 0)),
    method_(http::method::unknown),
    content(nullptr),
    keep_alive(false)
{
}

const status::status_type& request::unescape_path()
{
    path = unescape_uri(path, path.begin(), path_extension);
    
    // unsescaped path <= escaped and there are always '?' or space after path
    *path.end() = '\0';
    
    if (std::strstr(path.begin(), "..") != nullptr) {
        return http::status::bad_request;
    }
    
    return http::status::ok;
}

char_range_t request::unescape_uri(char_range_t src, char *dst, char_range_t &extension) noexcept
{
    char *dst_ptr = dst;
    char *src_ptr = src.begin();
    
    ngx_unescape_uri((unsigned char**)&dst_ptr, (unsigned char**)&src_ptr, src.size(), 0);
    
    char_range_t retval = char_range_t(dst, dst_ptr);
    
    if (retval.size() > 0) {
        for (char *p = retval.end() - 1; p >= retval.begin(); p--) {
            if (*p == '.') {
                extension = char_range_t(p + 1, retval.end());
                return retval;
            }
        }
    }
    
    extension = char_range_t(nullptr, nullptr);
    return retval;
}

std::ostream &operator<<(std::ostream &os, const request &req)
{
    os << "Dumping request:\n"
       << "  HTTP/" << req.http_version.first << '.' << req.http_version.second << '\n'
       << "  method: " << req.method_name << '\n'
       << "  schema: " << req.schema << '\n'
       << "  host: " << req.host << '\n'
       << "  port: " << req.port << '\n'
       << "  path: " << req.path << '\n'
       << "  path_extension: " << req.path_extension << '\n'
       << "  query_string: " << req.query_string << '\n'
       << "Headers:\n"
       << req.headers;
    
    return os;
}

}
}
